package srdb.migration;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import srdb.migration.common.IMTKConnection;
import srdb.migration.common.MTKBridge;
import srdb.migration.common.MTKConstants;
import srdb.migration.common.MTKData;
import srdb.migration.common.MTKMetaData;
import srdb.migration.dbhandler.enterprisedb.Data;
import srdb.migration.dbhandler.enterprisedb.NZData;
import srdb.migration.i18n.ResourceHandler;
import srdb.migration.schema.metadata.LargeBufferInputStream;
import srdb.migration.schema.metadata.Table;


public class DataLoader implements Runnable {
    private int numberOfThreads;
    private boolean truncateBeforeLoad;
    private char copyDelimeter;
    private boolean escapeTabDelimiter;
    private MigrationSummary summary;
    private MTKConstants.DATABASE_TYPE sourceDBType;
    private MTKConstants.DATABASE_TYPE targetDBType;
    private MigrationToolkit mtk;
    private List<Table> safeQue = new ArrayList<Table>();
    private List<Table> fastModeQue = new ArrayList<Table>();
    private List<Table> failedFastModeQue = new ArrayList<Table>();
    private List<Table> loQue = new ArrayList<Table>();
    private int currentSafeIndex = -1;
    private int currentFastModeIndex = -1;
    private int currentFailedFastModeIndex = -1;
    private int currentLoIndex = -1;
    private boolean copyTableDDL = false;
    private boolean flagFastCopy = false;
    private boolean offlineMigration = false;
    private boolean flagExitOnError = false;
    private boolean isDBLinkOra = false;
    private String targetSchema = null;
    private double totalTime = 0.0D;
    private long totalRows = 0L;
    private double totalSizeKBytes = 0.0D;

    private Map<String, ThreadInfo> threadInfoMap = null;
    ArrayList<Thread> listOfThreads = null;

    public DataLoader(int numberOfThreads, MigrationToolkit mtk,
                      MigrationSummary summary, MTKConstants.DATABASE_TYPE sourceDBType,
                      MTKConstants.DATABASE_TYPE targetDBType,
                      boolean truncateBeforeLoad, char copyDelimeter,
                      boolean escapeTabDelimiter, boolean copyTableDDL,
                      boolean flagFastCopy, boolean offlineMigration,
                      boolean flagExitOnError, boolean isDBLinkOra, String targetSchema)
            throws MTKException {
        this.numberOfThreads = numberOfThreads;
        this.mtk = mtk;
        this.summary = summary;
        this.sourceDBType = sourceDBType;
        this.targetDBType = targetDBType;
        this.truncateBeforeLoad = truncateBeforeLoad;
        this.copyDelimeter = copyDelimeter;
        this.escapeTabDelimiter = escapeTabDelimiter;
        this.copyTableDDL = copyTableDDL;
        this.flagFastCopy = flagFastCopy;
        this.offlineMigration = offlineMigration;
        this.flagExitOnError = flagExitOnError;
        this.isDBLinkOra = isDBLinkOra;
        this.targetSchema = targetSchema;
        initialize();
    }

    public void run() {
        boolean hasMoreFastModeData = true;
        while (hasMoreFastModeData) {
            try {
                hasMoreFastModeData = loadDataInFastMode();
            } catch (Exception ex) {
                ex.printStackTrace();
            }

        }
        while (loadDataInSafeMode())
            ;
        while (loadDataForFailedFastMode())
            ;
        while (loadDataForLoMode())
            ;
    }

    protected void startLoading() throws MTKException {
        this.listOfThreads = new ArrayList<Thread>();

        for (int i = 0; i < this.numberOfThreads; i++) {
            String threadName = "dataload_job_" + (i + 1);
            Thread t = new Thread(this);
            t.setName(threadName);
            this.listOfThreads.add(t);
            t.start();
        }
        for (int i = 0; i < this.listOfThreads.size(); i++)
            try {
                ((Thread) this.listOfThreads.get(i)).join();
            } catch (InterruptedException ex) {
            }
    }

    protected void initialize() throws MTKException {
        this.threadInfoMap = new HashMap();
        for (int i = 0; i < this.numberOfThreads; i++) {
            IMTKConnection srcConn = this.mtk.createNewSourceConnection();
            IMTKConnection targetConn = null;
            MTKMetaData targetMD = null;

            if (!this.mtk.offlineMigration()) {
                targetConn = this.mtk.createNewTargetConnection();
                targetMD = this.mtk.createTargetMetaData(targetConn);
                try {
                    targetMD.setSchema(this.mtk.targetSchema, false);

                    if ((this.targetDBType == MTKConstants.DATABASE_TYPE.ENTERPRISEDB)
                            || (this.targetDBType == MTKConstants.DATABASE_TYPE.NPS)
                            || (this.targetDBType == MTKConstants.DATABASE_TYPE.SRDB)) {
                        this.mtk.configPGGUCs(this.targetSchema,
                                this.targetDBType, targetMD);
                    }
                } catch (Exception e) {
                    throw new MTKException(e.getMessage());
                }
            }

            MTKData sourceData = this.mtk.mtkFactory.createMTKData(
                    this.sourceDBType, srcConn, MigrationToolkit.cpBatchSize);
            MTKData targetData = this.mtk.mtkFactory
                    .createMTKData(this.targetDBType, targetConn,
                            MigrationToolkit.cpBatchSize);

            ThreadInfo info = new ThreadInfo(srcConn, targetConn, targetMD,
                    sourceData, targetData, this.isDBLinkOra);
            String threadName = "dataload_job_" + (i + 1);
            this.threadInfoMap.put(threadName, info);
        }
    }

    private void operationFailed() {
        MigrationToolkit.incrementFailureCount();
    }

    private synchronized void rowsLoaded(long tableRows) {
        this.totalRows += tableRows;
    }

    private synchronized void rowsLoadedInTime(double tableTime) {
        this.totalTime += tableTime;
    }

    private synchronized void tableDataSize(double tableSizeKBytes) {
        this.totalSizeKBytes += tableSizeKBytes;
    }

    private synchronized Table nextSafeTable() {
        if (this.currentSafeIndex + 1 >= this.safeQue.size()) {
            return null;
        }

        this.currentSafeIndex += 1;
        return (Table) this.safeQue.get(this.currentSafeIndex);
    }

    private synchronized Table nextFastModeTable() {
        if (this.currentFastModeIndex + 1 >= this.fastModeQue.size()) {
            return null;
        }

        this.currentFastModeIndex += 1;
        return (Table) this.fastModeQue.get(this.currentFastModeIndex);
    }

    private synchronized Table nextFailedFastModeTable() {
        if (this.currentFailedFastModeIndex + 1 >= this.failedFastModeQue
                .size()) {
            return null;
        }

        this.currentFailedFastModeIndex += 1;
        return (Table) this.failedFastModeQue
                .get(this.currentFailedFastModeIndex);
    }

    private synchronized Table nextLoTable() {
        if (this.currentLoIndex + 1 >= this.loQue.size()) {
            return null;
        }

        this.currentLoIndex += 1;
        return (Table) this.loQue.get(this.currentLoIndex);
    }

    public void queDataForSafeMode(Table table) {
        this.safeQue.add(table);
    }

    public void queDataForLoMode(Table table) {
        this.loQue.add(table);
    }

    public void queDataForFailedFastMode(Table table) {
        this.failedFastModeQue.add(table);
    }

    public void queDataForFastMode(Table table) {
        this.fastModeQue.add(table);
    }

    public boolean loadDataInSafeMode() {
        Table table = nextSafeTable();

        if (table == null) {
            return false;
        }

        ThreadInfo info = (ThreadInfo) this.threadInfoMap.get(Thread
                .currentThread().getName());
        MTKMetaData targetMD = info.getTargetMD();
        try {
            this.summary.alertNewTable(table);
            Date startTime = new Date();
            long tableRows = 0L;
            String[] rbParameters = {table.getName()};
            MigrationToolkit.logMessage(ResourceHandler.getValue(
                    "INFO_LOADING_TABLE", rbParameters));

            if (this.truncateBeforeLoad) {
                if ((!table.isPartitioned())
                        || (MigrationToolkit
                        .isMemberOfPartitionTableList(table))) {
                    this.mtk.disableTableContraints(
                            table.getTargetSchemaFullyQualifiedName(
                                    this.sourceDBType, this.targetDBType, true),
                            targetMD);
                }

                if (this.mtk.flagGenStats)
                    this.mtk.dropTableConstsAndIndexes(table, targetMD);
                else {
                    this.mtk.disableTableIndexes(
                            table.getTargetSchemaFullyQualifiedName(
                                    this.sourceDBType, this.targetDBType, true),
                            targetMD);
                }
            }

            MTKBridge bridge = this.mtk.mtkFactory.createMTKBridge(
                    this.sourceDBType, this.targetDBType, info.getSourceConn(),
                    info.getTargetConn());
            tableRows += bridge.setTableDataInSafeMode(table,
                    this.sourceDBType, this.targetDBType);
            rowsLoaded(tableRows);

            this.summary.alertSuccessTable(table);

            Date endTime = new Date();
            double tableTime = endTime.getTime() - startTime.getTime();
            rowsLoadedInTime(tableTime);
            this.mtk.displayTableDataLoadSummary(table.getName(), tableTime,
                    tableRows, 0.0D);
        } catch (Exception lex) {
            lex.printStackTrace();
            operationFailed();
            String[] rbParameters = {table.getName(), lex.getMessage()};
            MigrationToolkit.logMessage(ResourceHandler.getValue(
                    "ERR_LOADING_DATA_IN_TABLE", rbParameters));
            Utility.getLogger().error("Stack Trace:", lex);
        }
        return true;
    }

    public boolean loadDataInFastMode() throws MTKException, SQLException {
        Table table = nextFastModeTable();

        if (table == null) {
            return false;
        }

        ThreadInfo info = (ThreadInfo) this.threadInfoMap.get(Thread
                .currentThread().getName());
        try {
            if (!this.mtk.offlineMigration()) {
                info.getTargetConn().setAutoCommit(false);
            }
            MTKMetaData targetMD = info.getTargetMD();
            MTKData sourceData = info.getSourceData();
            MTKData targetData = info.getTargetData();

            if ((this.copyTableDDL) && (this.flagFastCopy)) {
                try {
                    String[] rbParameters = {table.getName()};
                    MigrationToolkit.logMessage(ResourceHandler.getValue(
                            "INFO_CREATING_TABLE", rbParameters));
                    this.summary.alertNewTable(table);
                    targetMD.executeScript(this.mtk.tddl.getCreateScript(table));
                    this.summary.alertSuccessTable(table);
                } catch (Exception e) {
                    String[] rbParameters = {table.getName(), e.getMessage()};
                    Utility.getLogger()
                            .warn(ResourceHandler.getValue(
                                    "ERR_REATING_TABLE_WITH_MSG", rbParameters));
                    Utility.getLogger().error("Stack Trace:", e);
                    table.setCreationFailure(true);
                    try {
                        targetData.rollback();
                    } catch (Exception exp) {
                    }
                    operationFailed();

                    if (this.flagExitOnError) {
                        if (this.mtk.flagGenStats) {
                            this.mtk.propRepStats.setProperty("STATUS", "F");
                        }
                        info.getTargetConn().setAutoCommit(true);
                        throw new MTKException(ResourceHandler.getValue(
                                "ERR_TABLE_CREATION_FAIL_REASON",
                                new Object[]{table.getName(),
                                        this.targetDBType.getString(),
                                        e.getMessage()}));
                    }

                }

            }

            if ((this.targetDBType == MTKConstants.DATABASE_TYPE.ORACLE)
                    || (this.targetDBType == MTKConstants.DATABASE_TYPE.SQLSERVER)) {
                table.dataLoadFailed();
                this.summary.alertNewTable(table);
                this.summary.alertFailTable(table);
                info.getTargetConn().setAutoCommit(true);
                // e = 1;
                // return e;
                return false;
            }
            double tableTime = 0.0D;
            long tableRows = 0L;
            double tableSizeKBytes = 0.0D;

            if (!table.isCreationFailure()) {
                if (!table.hasLargeObject()) { // xlob 类型，二进制类型，数据迁移 见
                    // loadDataForLoMode
                    try {
                        this.summary.alertNewTable(table);
                        if (this.truncateBeforeLoad) {
                            this.mtk.disableTableContraints(table
                                    .getTargetSchemaFullyQualifiedName(
                                            this.sourceDBType,
                                            this.targetDBType, true), targetMD);
                            String[] rbParameters = {table.getName()};
                            if (!this.isDBLinkOra) {
                                MigrationToolkit.logMessage(ResourceHandler
                                        .getValue("INFO_TRUNCATING_TABLE",
                                                rbParameters));
                            }

                            if ((table.isPartitioned())
                                    && (!MigrationToolkit
                                    .isMemberOfPartitionTableList(table)))
                                targetMD.executeScript("DELETE FROM "
                                        + table.getTargetSchemaFullyQualifiedName(
                                        this.sourceDBType,
                                        this.targetDBType, false));
                            else if (!this.isDBLinkOra) {
                                targetMD.executeScript("Truncate Table "
                                        + table.getTargetSchemaFullyQualifiedName(
                                        this.sourceDBType,
                                        this.targetDBType, false));
                            }

                            if (((table.isPartitioned()) && (!MigrationToolkit
                                    .isMemberOfPartitionTableList(table)))
                                    || (this.mtk.enableConstBeforeDataLoad)) {
                                this.mtk.enableTableContraints(table
                                                .getTargetSchemaFullyQualifiedName(
                                                        this.sourceDBType,
                                                        this.targetDBType, true),
                                        targetMD);
                            }

                            if (this.mtk.flagGenStats)
                                this.mtk.dropTableConstsAndIndexes(table,
                                        targetMD);
                            else {
                                this.mtk.disableTableIndexes(table
                                                .getTargetSchemaFullyQualifiedName(
                                                        this.sourceDBType,
                                                        this.targetDBType, true),
                                        targetMD);
                            }
                        }

                        String[] rbParameters = {table.getName()};
                        MigrationToolkit.logMessage(ResourceHandler.getValue(
                                "INFO_LOADING_TABLE", rbParameters));
                        Date startTime = new Date();

                        if (this.isDBLinkOra) {
                            tableRows = targetData.setTableDataViaDBLinkOra(
                                    table.getFullName(true), this.targetSchema,
                                    table.getTargetTableName(this.sourceDBType,
                                            this.targetDBType, false),
                                    this.truncateBeforeLoad);
                        } else {
                            //获取源库数据
                            LargeBufferInputStream pis = sourceData
                                    .getTableData(this.sourceDBType,
                                            this.targetDBType, table,
                                            this.copyDelimeter,
                                            this.escapeTabDelimiter);

                            String nzMaxRowsStr = MigrationToolkit
                                    .getNZOptionValue("maxRows");
                            int nzMaxRows = 0;
                            try {
                                nzMaxRows = Integer.parseInt(nzMaxRowsStr);
                            } catch (Exception e) {
                            }
                            boolean maxRowsFlag = nzMaxRows > 0;
                            long oldRowCount = 0L;
                            //数据迁移
                            while (pis != null) {
                                oldRowCount = tableRows;
                                tableRows += pis.getNumRows();
//								Utility.getLogger().info(tableRows);
                                tableSizeKBytes += pis.getLength() / 1024;
                                targetData.setTableData(table
                                                .getTargetSchemaFullyQualifiedName(
                                                        this.sourceDBType,
                                                        this.targetDBType, false), pis,
                                        this.copyDelimeter);
                                long skipped = 0L;
                                if ((targetData instanceof NZData)) {
                                    skipped = ((NZData) targetData)
                                            .getBadRows();
                                }
                                tableRows -= skipped;

                                if (oldRowCount != tableRows) {
                                    if (!maxRowsFlag)
                                        rbParameters = new String[]{String
                                                .valueOf(tableRows)};
                                    else {
                                        rbParameters = new String[]{String
                                                .valueOf(nzMaxRows < pis
                                                        .getNumRows() ? oldRowCount
                                                        + nzMaxRows - skipped
                                                        : tableRows)};
                                    }

                                    MigrationToolkit.logMessage("["
                                            + table.getName()
                                            + "] "
                                            + ResourceHandler.getValue(
                                            "INFO_MIGRATED_ROWS",
                                            rbParameters));
                                }

                                if (maxRowsFlag) {
                                    if (nzMaxRows <= pis.getNumRows()) {
                                        tableRows = oldRowCount + nzMaxRows
                                                - skipped;
                                        break;
                                    }

                                    nzMaxRows -= pis.getNumRows();
                                }

                                pis = sourceData.getTableData(
                                        this.sourceDBType, this.targetDBType,
                                        table, this.copyDelimeter,
                                        this.escapeTabDelimiter);
                            }

                            if (pis != null) {
                                pis.close();
                            }

                        }

                        if ((!this.offlineMigration) && (this.flagFastCopy)
                                && (!this.isDBLinkOra)) {
                            targetData.commit();
                        }

                        if (this.mtk.flagGenStats) {
                            this.mtk.propRepStats.setProperty(
                                    table.getFullName(true),
                                    String.valueOf(tableRows));
                        }

                        Date endTime = new Date();
                        tableTime = endTime.getTime() - startTime.getTime();
                        rowsLoadedInTime(tableTime);
                        rowsLoaded(tableRows);
                        tableDataSize(tableSizeKBytes);
                        this.mtk.displayTableDataLoadSummary(table.getName(),
                                tableTime, tableRows, tableSizeKBytes);
                        this.summary.alertSuccessTable(table);
                        /**
                         * 完成迁移一张表,增加迁移表数目
                         */
                        mtk.addMigratedTables();

                    } catch (Exception dex) {
                        if (this.targetDBType == MTKConstants.DATABASE_TYPE.NPS) {
                            this.summary.alertFailTable(table);
                            operationFailed();
                        }

                        table.dataLoadFailed();

                        if ((this.flagFastCopy) && (!this.isDBLinkOra))
                            try {
                                targetData.rollback();
                            } catch (Exception exp) {
                            }
                        sourceData.reset();

                        if (dex.getMessage().contains(
                                "Rreport_invalid_encoding")) {
                            String[] rbParameters = {
                                    table.getName(),
                                    ResourceHandler.getValue(
                                            "ERR_ENCODING_MESSAGE", null)};

                            MigrationToolkit.logMessage(ResourceHandler
                                    .getValue("ERR_LOADING_DATA_IN_TABLE",
                                            rbParameters));
                        } else {
                            String[] rbParameters = {table.getName(),
                                    dex.getMessage()};
                            MigrationToolkit.logMessage(ResourceHandler
                                    .getValue("ERR_LOADING_DATA_IN_TABLE",
                                            rbParameters));
                        }

                    }

                } else if ((this.copyTableDDL) && (this.flagFastCopy)
                        && (!this.isDBLinkOra)) {
                    try {
                        targetData.commit();
                    } catch (Exception exp) {
                    }

                }

            }

        } finally {
            if (!this.mtk.offlineMigration()) {
                info.getTargetConn().setAutoCommit(true);
            }
        }

        return true;
    }

    public boolean loadDataForFailedFastMode() {
        Table table = nextFailedFastModeTable();

        if (table == null) {
            return false;
        }

        ThreadInfo info = (ThreadInfo) this.threadInfoMap.get(Thread
                .currentThread().getName());
        MTKMetaData targetMD = info.getTargetMD();

        table.resetBatchFailureCount();
        double tableTime = 0.0D;
        long tableRows = 0L;
        double tableSizeKBytes = 0.0D;
        try {
            if ((this.copyTableDDL) && (this.flagFastCopy)) {
                try {
                    this.summary.alertNewTable(table);
                    targetMD.executeScript(this.mtk.tddl.getCreateScript(table));
                    this.summary.alertSuccessTable(table);
                } catch (Exception e) {
                    String[] rbParameters = {table.getName(), e.getMessage()};
                    Utility.getLogger()
                            .warn(ResourceHandler.getValue(
                                    "ERR_REATING_TABLE_WITH_MSG", rbParameters));
                    Utility.getLogger().error("Stack Trace:", e);
                    table.setCreationFailure(true);
                    operationFailed();

                    if (this.flagExitOnError) {
                        if (this.mtk.flagGenStats) {
                            this.mtk.propRepStats.setProperty("STATUS", "F");
                        }

                        throw new MTKException(ResourceHandler.getValue(
                                "ERR_TABLE_CREATION_FAIL_REASON",
                                new Object[]{table.getName(),
                                        this.targetDBType.getString(),
                                        e.getMessage()}));
                    }
                }

            }

            Date startTime = new Date();
            if (this.truncateBeforeLoad) {
                if ((!table.isPartitioned())
                        || (MigrationToolkit
                        .isMemberOfPartitionTableList(table))) {
                    this.mtk.disableTableContraints(
                            table.getTargetSchemaFullyQualifiedName(
                                    this.sourceDBType, this.targetDBType, true),
                            targetMD);
                }

                if (this.mtk.flagGenStats)
                    this.mtk.dropTableConstsAndIndexes(table, targetMD);
                else {
                    this.mtk.disableTableIndexes(
                            table.getTargetSchemaFullyQualifiedName(
                                    this.sourceDBType, this.targetDBType, true),
                            targetMD);
                }

            }

            if ((this.targetDBType == MTKConstants.DATABASE_TYPE.ENTERPRISEDB)
                    || (this.targetDBType == MTKConstants.DATABASE_TYPE.SRDB)) {
                String[] rbParameters = {table.getName(),
                        String.valueOf(MigrationToolkit.batchSize)};
                MigrationToolkit.logMessage(ResourceHandler.getValue(
                        "INFO_TRYING_TO_RELOAD_TABLE", rbParameters));
            }

            this.summary.alertFailTable(table);

            MTKBridge bridge = this.mtk.mtkFactory.createMTKBridge(
                    this.sourceDBType, this.targetDBType, info.getSourceConn(),
                    info.getTargetConn());
            tableRows = bridge.setTableData(table, MigrationToolkit.batchSize,
                    this.sourceDBType, this.targetDBType);
            tableSizeKBytes = bridge.getLastMigratedDataSize() / 1024L;

            if (table.getBatchFailureCount() == 0) {
                this.summary.alertSuccessTable(table);
            }

            if (this.mtk.flagGenStats) {
                this.mtk.propRepStats.setProperty(table.getFullName(true),
                        String.valueOf(tableRows));
            }

            Date endTime = new Date();
            tableTime = endTime.getTime() - startTime.getTime();
            rowsLoadedInTime(tableTime);
            rowsLoaded(tableRows);
            tableDataSize(tableSizeKBytes);
            this.mtk.displayTableDataLoadSummary(table.getName(), tableTime,
                    tableRows, tableSizeKBytes);
        } catch (Exception lex) {
            lex.printStackTrace();
            operationFailed();
            String[] rbParameters = {table.getName(), lex.getMessage()};
            MigrationToolkit.logMessage(ResourceHandler.getValue(
                    "ERR_LOADING_DATA_IN_TABLE", rbParameters));
        }
        return true;
    }

    public boolean loadDataForLoMode() {
        Table table = nextLoTable();
        if (table == null) {
            return false;
        }

        ThreadInfo info = (ThreadInfo) this.threadInfoMap.get(Thread
                .currentThread().getName());
        MTKMetaData targetMD = info.getTargetMD();

        table.resetBatchFailureCount();
        double tableTime = 0.0D;
        long tableRows = 0L;
        double tableSizeKBytes = 0.0D;

        if (!table.isCreationFailure()) {
            try {
                if (table.hasLargeObject()) {
                    Date startTime = new Date();
                    if (this.truncateBeforeLoad) {
                        if ((!table.isPartitioned())
                                || (MigrationToolkit
                                .isMemberOfPartitionTableList(table))) {
                            this.mtk.disableTableContraints(table
                                    .getTargetSchemaFullyQualifiedName(
                                            this.sourceDBType,
                                            this.targetDBType, true), targetMD);
                        }

                        if (this.mtk.flagGenStats)
                            this.mtk.dropTableConstsAndIndexes(table, targetMD);
                        else {
                            this.mtk.disableTableIndexes(table
                                    .getTargetSchemaFullyQualifiedName(
                                            this.sourceDBType,
                                            this.targetDBType, true), targetMD);
                        }
                    }

                    String[] rbParameters = {table.getName()};// 加载大字段数据
                    MigrationToolkit.logMessage(ResourceHandler
                            .getValue("INFO_LOADING_LARGE_OBJECTS_IN_TABLE",
                                    rbParameters));
                    this.summary.alertNewTable(table);
                    if (this.isDBLinkOra) {
                        tableRows = info.getTargetData()
                                .setTableDataViaDBLinkOra(
                                        table.getFullName(true),
                                        this.targetSchema,
                                        table.getTargetTableName(
                                                this.sourceDBType,
                                                this.targetDBType, false),
                                        this.truncateBeforeLoad);
                    } else {
                        MTKBridge bridge = this.mtk.mtkFactory.createMTKBridge(
                                this.sourceDBType, this.targetDBType,
                                info.getSourceConn(), info.getTargetConn());
                        // ================================
                        tableRows = bridge.setTableData(table,
                                MigrationToolkit.lobBatchSize,
                                this.sourceDBType, this.targetDBType);
                        tableSizeKBytes = bridge.getLastMigratedDataSize() / 1024L;
                    }
                    if (table.getBatchFailureCount() == 0) {
                        this.summary.alertSuccessTable(table);
                    }

                    if (this.mtk.flagGenStats) {
                        this.mtk.propRepStats.setProperty(
                                table.getFullName(true),
                                String.valueOf(tableRows));
                    }

                    Date endTime = new Date();
                    tableTime = endTime.getTime() - startTime.getTime();
                    rowsLoadedInTime(tableTime);
                    rowsLoaded(tableRows);
                    tableDataSize(tableSizeKBytes);
                    this.mtk.displayTableDataLoadSummary(table.getName(),
                            tableTime, tableRows, tableSizeKBytes);
                }
            } catch (Exception lex) {

//				lex.printStackTrace();
//				modify by kevin
                operationFailed();
                String[] rbParameters = {table.getName(), lex.getMessage()};
                MigrationToolkit.logMessage(ResourceHandler.getValue(
                        "ERR_LOADING_DATA_IN_TABLE", rbParameters));
            }
        }
        return true;
    }

    public long getTotalRows() {
        return this.totalRows;
    }

    public double getTotalTime() {
        return this.totalTime;
    }

    public double getTotalDataSize() {
        return this.totalSizeKBytes;
    }

    public void finalize() {
        if (this.threadInfoMap == null) {
            return;
        }
        Iterator keys = this.threadInfoMap.keySet().iterator();
        while (keys.hasNext()) {
            String key = (String) keys.next();
            ((ThreadInfo) this.threadInfoMap.get(key)).destroy();
        }

        this.threadInfoMap.clear();
        this.threadInfoMap = null;
        this.listOfThreads = null;
    }

    private class ThreadInfo {
        private IMTKConnection srcConn = null;
        private IMTKConnection targetConn = null;
        private MTKMetaData targetMD = null;
        private MTKData sourceData = null;
        private MTKData targetData = null;
        private boolean DBLinkLoaded = false;

        public ThreadInfo(IMTKConnection srcConn, IMTKConnection targetConn,
                          MTKMetaData targetMD, MTKData sourceData, MTKData targetData,
                          boolean isDBLinkOra) throws MTKException {
            this.srcConn = srcConn;
            this.targetConn = targetConn;
            this.targetMD = targetMD;
            this.sourceData = sourceData;
            this.targetData = targetData;

            if (isDBLinkOra)
                try {
                    DataLoader.this.mtk.connectDBLinkOra(targetData);
                    this.DBLinkLoaded = true;
                } catch (SQLException sqle) {
                    throw new MTKException(sqle);
                }
        }

        IMTKConnection getSourceConn() {
            return this.srcConn;
        }

        IMTKConnection getTargetConn() {
            return this.targetConn;
        }

        MTKMetaData getTargetMD() {
            return this.targetMD;
        }

        void destroy() {
            if (this.DBLinkLoaded)
                try {
                    ((Data) this.targetData).disConnectDBlinkOra();
                    this.DBLinkLoaded = false;
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            try {
                this.srcConn.getConnection().close();
            } catch (Exception exp) {
            }
            try {
                this.targetConn.getConnection().close();
            } catch (Exception exp) {
            }
        }

        public MTKData getSourceData() {
            return this.sourceData;
        }

        public void setSourceData(MTKData sourceData) {
            this.sourceData = sourceData;
        }

        public MTKData getTargetData() {
            return this.targetData;
        }

        public void setTargetData(MTKData targetData) {
            this.targetData = targetData;
        }
    }
}

/*

 */